package com.itheima.sfbx.insurance.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.itheima.sfbx.framework.commons.constant.basic.SuperConstant;
import com.itheima.sfbx.framework.commons.constant.insure.InsureConstant;
import com.itheima.sfbx.framework.commons.dto.basic.TreeItemVO;
import com.itheima.sfbx.framework.commons.dto.basic.TreeVO;
import com.itheima.sfbx.framework.commons.exception.ProjectException;
import com.itheima.sfbx.framework.commons.utils.BeanConv;
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
import com.itheima.sfbx.framework.commons.utils.NoProcessing;
import com.itheima.sfbx.insurance.dto.CategoryCoefficentVO;
import com.itheima.sfbx.insurance.dto.CategoryConditionVO;
import com.itheima.sfbx.insurance.dto.CategorySafeguardVO;
import com.itheima.sfbx.insurance.dto.CategoryVO;
import com.itheima.sfbx.insurance.enums.CategoryEnum;
import com.itheima.sfbx.insurance.mapper.CategoryMapper;
import com.itheima.sfbx.insurance.pojo.Category;
import com.itheima.sfbx.insurance.pojo.CategoryCoefficent;
import com.itheima.sfbx.insurance.pojo.CategoryCondition;
import com.itheima.sfbx.insurance.pojo.CategorySafeguard;
import com.itheima.sfbx.insurance.service.ICategoryCoefficentService;
import com.itheima.sfbx.insurance.service.ICategoryConditionService;
import com.itheima.sfbx.insurance.service.ICategorySafeguardService;
import com.itheima.sfbx.insurance.service.ICategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description：保险分类服务实现类
 */
@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements ICategoryService {

    @Autowired
    ICategoryConditionService categoryConditionService;

    @Autowired
    ICategoryCoefficentService categoryCoefficentService;

    @Autowired
    ICategorySafeguardService categorySafeguardService;


    @Override
    public Page<CategoryVO> findPage(CategoryVO categoryVO, int pageNum, int pageSize) {

        Page<Category> page = this.page(new Page<>(pageNum, pageSize), queryWrapper(categoryVO));

        Page<CategoryVO> voPage = BeanConv.toPage(page, CategoryVO.class);
        List<CategoryVO> categoryList = voPage.getRecords();

        if(CollUtil.isEmpty(categoryList)){
            return voPage;
        }

        Set<String> noSet = categoryList.stream().map(CategoryVO::getCategoryNo).collect(Collectors.toSet());

        List<CategoryCondition> categoryConditionList = categoryConditionService.lambdaQuery()
                .in(CategoryCondition::getCategoryNo, noSet)
                .list();
        List<CategoryCoefficent> categoryCoefficentList = categoryCoefficentService.lambdaQuery()
                .in(CategoryCoefficent::getCategoryNo, noSet)
                .list();
        List<CategorySafeguard> categorySafeguardList = categorySafeguardService.lambdaQuery()
                .in(CategorySafeguard::getCategoryNo, noSet)
                .list();

        for (CategoryVO vo : categoryList) {
            List<CategoryConditionVO> conditionVOS = BeanConv.toBeanList(categoryConditionList, CategoryConditionVO.class);
            vo.setCategoryConditionVOs(conditionVOS);

            List<CategoryCoefficentVO> coefficentVOS = BeanConv.toBeanList(categoryCoefficentList, CategoryCoefficentVO.class);
            vo.setCategoryCoefficentVOs(coefficentVOS);

            List<CategorySafeguardVO> safeguardVOS = BeanConv.toBeanList(categorySafeguardList, CategorySafeguardVO.class);
            vo.setCategorySafeguardVOs(safeguardVOS);
        }

        return voPage;
    }

    @Override
    @Transactional
    public CategoryVO save(CategoryVO categoryVO) {

        // 查询是否存在该名称
        Integer count = lambdaQuery()
                .eq(Category::getCategoryName, categoryVO.getCategoryName())
                .eq(Category::getDataState, SuperConstant.DATA_STATE_0)
                .count();
        if(count>0){
            log.error("新增失败，已存在该数据");
            throw new ProjectException(CategoryEnum.SAVE_FAIL);
        }

        Category category = BeanConv.toBean(categoryVO, Category.class);
        category.setCategoryNo(this.createCategoryNo(categoryVO.getParentCategoryNo()));

        save(category);

        return BeanConv.toBean(category, CategoryVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(CategoryVO categoryVO) {

        // 判断是否存在
        Category bean = getById(categoryVO.getId());
        if(bean==null){
            log.error("更新失败，不存在该数据");
            throw new ProjectException(CategoryEnum.UPDATE_FAIL);
        }

        // 查询名字是否重复
        Integer count = lambdaQuery()
                .eq(Category::getCategoryName, categoryVO.getCategoryName())
                .ne(Category::getId, categoryVO.getId())
                .count();
        if(count>0){
            log.error("更新失败，该name重复");
            throw new ProjectException(CategoryEnum.UPDATE_FAIL);
        }

        updateById(BeanConv.toBean(categoryVO, Category.class));

        // 关联项删除
        categoryCoefficentService.deleteByCategoryNo(categoryVO.getCategoryNo());
        categoryConditionService.deleteByCategoryNo(categoryVO.getCategoryNo());
        categorySafeguardService.deleteByCategoryNo(categoryVO.getCategoryNo());

        // 关联项新增
        List<CategorySafeguardVO> categorySafeguardVOs = categoryVO.getCategorySafeguardVOs();
        if(CollUtil.isNotEmpty(categorySafeguardVOs)){
            categorySafeguardVOs.forEach(c->c.setCategoryNo(categoryVO.getCategoryNo()));
            categorySafeguardService.saveBatch(BeanConv.toBeanList(categorySafeguardVOs, CategorySafeguard.class));
        }
        List<CategoryCoefficentVO> categoryCoefficentVOs = categoryVO.getCategoryCoefficentVOs();
        if(CollUtil.isNotEmpty(categoryCoefficentVOs)){
            categoryCoefficentVOs.forEach(c->c.setCategoryNo(categoryVO.getCategoryNo()));
            categoryCoefficentService.saveBatch(BeanConv.toBeanList(categoryCoefficentVOs, CategoryCoefficent.class));
        }
        List<CategoryConditionVO> categoryConditionVOS = categoryVO.getCategoryConditionVOs();
        if(CollUtil.isNotEmpty(categoryConditionVOS)){
            categoryConditionVOS.forEach(c->c.setCategoryNo(categoryVO.getCategoryNo()));
            categoryConditionService.saveBatch(BeanConv.toBeanList(categoryConditionVOS, CategoryCondition.class));
        }

        return true;
    }

    @Override
    @Transactional
    public Boolean delete(String[] checkedIds) {

        // 查看id是否存在
        Category bean = getById(checkedIds[0]);
        if(bean==null){
            log.error("删除分类失败，该数据不存在");
            throw new ProjectException(CategoryEnum.DEL_FAIL);
        }

        // 判断是否有子节点
        String head = NoProcessing.processString(bean.getCategoryNo());
        Integer count = lambdaQuery()
                .likeRight(Category::getParentCategoryNo, head)
                .count();
        if(count > 0){
            log.error("删除分类失败，存在子节点");
            throw new ProjectException(CategoryEnum.DEL_FAIL);
        }

        // 判断是否有关联项
        Integer count1 = categoryConditionService.lambdaQuery()
                .eq(CategoryCondition::getCategoryNo, bean.getCategoryNo())
                .count();

        Integer count2 = categoryCoefficentService.lambdaQuery()
                .eq(CategoryCoefficent::getCategoryNo, bean.getCategoryNo())
                .count();

        Integer count3 = categorySafeguardService.lambdaQuery()
                .eq(CategorySafeguard::getCategoryNo, bean.getCategoryNo())
                .count();

        if(count1 > 0 || count2 > 0 || count3 > 0){
            log.error("删除分类失败，存在关联项");
            throw new ProjectException(CategoryEnum.DEL_FAIL);
        }

        int result = baseMapper.deleteById(checkedIds[0]);

        return result > 0;
    }

    @Override
    public List<CategoryVO> findList(CategoryVO query) {
        //构建查询条件，和page分页一样，可以整合
        List<Category> categorys = lambdaQuery().like(StrUtil.isNotBlank(query.getCategoryName()), Category::getCategoryName, query.getCategoryName())
                .eq(StrUtil.isNotBlank(query.getCategoryNo()), Category::getCategoryNo, query.getCategoryNo())
                .eq(StrUtil.isNotBlank(query.getCheckRule()), Category::getCheckRule, query.getCheckRule())
                .eq(StrUtil.isNotBlank(query.getDataState()), Category::getDataState, query.getDataState())
                .eq(StrUtil.isNotBlank(query.getCategoryType()), Category::getCategoryType, query.getCategoryType())
                .eq(StrUtil.isNotBlank(query.getParentCategoryNo()), Category::getParentCategoryNo, query.getParentCategoryNo()).list();
        List<Category> categorysHandler = Lists.newArrayList();
        //显示指定节点层
        if (!EmptyUtil.isNullOrEmpty(query.getNodeFloors())){
            categorys.forEach(n->{
                //NoProcessing就是根据No判断层级的一个工具类
                if (query.getNodeFloors().contains((long) (NoProcessing.processString(n.getCategoryNo()).length() / 3 - 1))){
                    categorysHandler.add(n);
                }
            });
        }else {
            categorysHandler.addAll(categorys);
        }
        //执行列表查询
        List<CategoryVO> categoryVOs = BeanConv.toBeanList(categorysHandler,CategoryVO.class);
        if (!EmptyUtil.isNullOrEmpty(categoryVOs)){
            Set<String> categoryNoSet = categoryVOs.stream().map(CategoryVO::getCategoryNo).collect(Collectors.toSet());
            //查询分类筛选项
            List<CategoryConditionVO> categoryConditionVOs = categoryConditionService.findListInCategoryNo(categoryNoSet);
            //查询分类保障项
            List<CategorySafeguardVO> categorySafeguardVOs = categorySafeguardService.findListInCategoryNo(categoryNoSet);
            //查询分类系数项
            List<CategoryCoefficentVO> categoryCoefficentVOs = categoryCoefficentService.findListInCategoryNo(categoryNoSet);
            //组合表单，双重for，也可以参考转Map的方式，自己选择，这里只是提供思路
            categoryVOs.forEach(n->{
                n.setCategoryConditionVOs(categoryConditionVOs.stream()
                        .filter(y->n.getCategoryNo().equals(y.getCategoryNo()))
                        .collect(Collectors.toList()));
                n.setCategoryCoefficentVOs(categoryCoefficentVOs.stream()
                        .filter(y->n.getCategoryNo().equals(y.getCategoryNo()))
                        .collect(Collectors.toList()));
                n.setCategorySafeguardVOs(categorySafeguardVOs.stream()
                        .filter(y->n.getCategoryNo().equals(y.getCategoryNo()))
                        .collect(Collectors.toList()));
            });
        }
        return categoryVOs;
    }



    @Override
    public TreeVO categoryTreeVO(String parentCategoryNo, String categoryType,String[] checkedCategoryNos) {
        // 确定根节点
        String root = StrUtil.isBlank(parentCategoryNo) ? SuperConstant.ROOT_PARENT_ID : parentCategoryNo;

        // 根节点下及其所有子节点
        String head = NoProcessing.processString(root);

        // 查询所有分类
        List<Category> categoryList = lambdaQuery()
                .likeRight(Category::getCategoryNo, head)
                .eq(StrUtil.isNotBlank(categoryType), Category::getCategoryType, categoryType)
                .list();

        // 分类list转成treeVoList
        List<TreeItemVO> voList = categoryList.stream().map(ca -> TreeItemVO.builder()
                .id(ca.getCategoryNo())
                .parentId(ca.getParentCategoryNo())
                .label(ca.getCategoryName())
                .build())
                .collect(Collectors.toList());

        // 聚合，key是父id，value是所有子节点
        Map<String, List<TreeItemVO>> treeMap = voList.stream().collect(Collectors.groupingBy(TreeItemVO::getParentId));

        // 遍历treeVoList给每一个item配孩子
        for (TreeItemVO treeItemVO : voList) {
            List<TreeItemVO> treeItemVOS = treeMap.get(treeItemVO.getId());
            treeItemVO.setChildren(treeItemVOS);
        }

        TreeVO treeVO = new TreeVO();
        treeVO.setItems(treeMap.get(root));
        return treeVO;
    }

    @Override
    public String createCategoryNo(String parentCategoryNo) {
        CategoryVO categoryVO = CategoryVO.builder()
            .parentCategoryNo(parentCategoryNo)
            .build();
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Category::getParentCategoryNo,parentCategoryNo);
        List<Category> categoryList = list(queryWrapper);
        //无下属节点则创建下属节点
        if (EmptyUtil.isNullOrEmpty(categoryList)){
            return NoProcessing.createNo(parentCategoryNo,false);
        //有下属节点则累加下属节点
        }else {
            Long categoryNo = categoryList.stream()
                .map(category -> { return Long.valueOf(category.getCategoryNo());})
                .max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(categoryNo),true);
        }
    }

    /**
     * 人种榜险种榜分类
      * @param type
     */
    @Override
    public List<CategoryVO> categoryCheckRule(String type) {
        //判断是否是险种榜
        if(InsureConstant.checkIsInsureType(type)){
            List<CategoryVO> res = new ArrayList<>();
            //获取所有的险种榜
            List<String> allCheckRule = InsureConstant.getAllCheckRule();
            allCheckRule.forEach(e->{
                CategoryVO categoryVO = CategoryVO.builder().categoryNo(e).categoryName(InsureConstant.getRuleNameById(e)).build();
                res.add(categoryVO);
            });
            return res;
        }else{
            //说明是人种榜
            List<String> categoryNames = Arrays.asList("成年人", "少儿", "老人");
            LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(Category::getCategoryName,categoryNames);
            queryWrapper.eq(Category::getDataState,SuperConstant.DATA_STATE_0);
            List<CategoryVO> res = BeanConv.toBeanList(list(queryWrapper), CategoryVO.class);
            return res;
        }
    }


    private LambdaQueryWrapper<Category> queryWrapper(CategoryVO categoryVO){
        LambdaQueryWrapper<Category> lqw = new LambdaQueryWrapper<>();
        lqw.eq(StrUtil.isNotBlank(categoryVO.getParentCategoryNo()), Category::getParentCategoryNo, categoryVO.getParentCategoryNo())
        .eq(StrUtil.isNotBlank(categoryVO.getCategoryNo()), Category::getCategoryNo, categoryVO.getCategoryNo())
        .like(StrUtil.isNotBlank(categoryVO.getCategoryName()), Category::getCategoryName, categoryVO.getCategoryName())
        .eq(StrUtil.isNotBlank(categoryVO.getCheckRule()), Category::getCheckRule, categoryVO.getCheckRule())
        .eq(StrUtil.isNotBlank(categoryVO.getDataState()), Category::getDataState, categoryVO.getDataState())
        .eq(StrUtil.isNotBlank(categoryVO.getLeafNode()), Category::getLeafNode, categoryVO.getLeafNode())
        .eq(StrUtil.isNotBlank(categoryVO.getShowIndex()), Category::getShowIndex, categoryVO.getShowIndex())
        .eq(StrUtil.isNotBlank(categoryVO.getCategoryType()), Category::getCategoryType, categoryVO.getCategoryType());
        return lqw;
    }
}
